﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using AutoLoL.Entities;
using AutoLoL.Logic.Utils;
using AutoLoL.Shared;

namespace AutoLoL.Logic
{
    public class ItemRepository
    {
        private static ReadOnlyCollection<Item> _items;

        public static Item GetByItemId(int itemId)
        {
            if (itemId > 0)
            {
                return GetAll().Where(c => c.ItemId == itemId).SingleOrDefault();
            }

            return null;
        }

        public static ReadOnlyCollection<Item> GetAll(bool cached = true)
        {
            if (_items == null || !cached)
            {
                List<Item> items = new List<Item>();

                Dictionary<Item, int[]> builtFromMapping = new Dictionary<Item, int[]>();
                Dictionary<Item, int[]> buildsIntoMapping = new Dictionary<Item, int[]>();

                if (File.Exists(Constants.ITEMS_XML_FILE))
                {
                    XDocument itemsDoc = XDocument.Load(Constants.ITEMS_XML_FILE);
                    foreach (XElement itemElement in itemsDoc.Root.Elements("item"))
                    {
                        int id = int.Parse(itemElement.Element("id").Value);
                        string name = itemElement.Element("name").Value;
                        string icon = itemElement.Element("icon").Value;
                        string description = itemElement.Element("description").Value;
                        int price = int.Parse(itemElement.Element("price").Value);

                        string iconPath = Path.Combine(Constants.ITEMS_DIRECTORY, icon);

                        Item item = new Item();
                        item.ItemId = id;
                        item.Name = name;
                        item.IconBitmapImage = ImageConverter.ConvertFileToBitmapImage(iconPath);
                        item.Description = description;
                        item.Price = price;

                        #region Built From
                        List<int> builtFromList = new List<int>();
                        foreach (XElement builtFromElement in itemElement.Element("built_from").Elements("item"))
                        {
                            int builtFromid = int.Parse(builtFromElement.Attribute("id").Value);
                            if (!builtFromList.Contains(builtFromid))
                            {
                                builtFromList.Add(builtFromid);
                            }
                        }

                        builtFromMapping.Add(item, builtFromList.ToArray());
                        #endregion

                        #region Builds Into
                        List<int> buildsIntoList = new List<int>();
                        foreach (XElement buildsIntoElement in itemElement.Element("builds_into").Elements("item"))
                        {
                            int buildsIntoId = int.Parse(buildsIntoElement.Attribute("id").Value);
                            if (!buildsIntoList.Contains(buildsIntoId))
                            {
                                buildsIntoList.Add(buildsIntoId);
                            }
                        }

                        buildsIntoMapping.Add(item, buildsIntoList.ToArray());
                        #endregion

                        items.Add(item);
                    }
                }

                #region Built From
                foreach (Item item in builtFromMapping.Keys)
                {
                    List<Item> builtFromItems = new List<Item>();
                    foreach (int builtFromId in builtFromMapping[item])
                    {
                        Item builtFromItem = items.Where(c => c.ItemId == builtFromId).SingleOrDefault();
                        builtFromItems.Add(builtFromItem);
                    }

                    item.BuiltFrom = builtFromItems.ToArray();
                }
                #endregion

                #region Builds Into
                foreach (Item item in buildsIntoMapping.Keys)
                {
                    List<Item> buildsIntoItems = new List<Item>();
                    foreach (int buildsIntoId in buildsIntoMapping[item])
                    {
                        Item buildsIntoItem = items.Where(c => c.ItemId == buildsIntoId).SingleOrDefault();
                        buildsIntoItems.Add(buildsIntoItem);
                    }

                    item.BuildsInto = buildsIntoItems.ToArray();
                }
                #endregion

                SetItemTotals(items);

                items.Sort((x1, x2) => x1.Name.CompareTo(x2.Name));
                _items = new ReadOnlyCollection<Item>(items);
            }

            return _items;
        }

        private static void SetItemTotals(List<Item> items)
        {
            foreach (Item item in items)
            {
                item.Total = -1;
            }

            foreach (Item item in items.Where(c => c.BuiltFrom.Length == 0))
            {
                item.Total = item.Price;
            }

            int iterations = 0;
            while (items.Where(c => c.BuiltFrom.Length > 0 && c.Total == -1).Any() && iterations < 100)
            {
                foreach (Item item in items.Where(c => c.BuiltFrom.Length > 0 && c.Total == -1))
                {
                    int total = 0;
                    bool failed = false;

                    foreach (Item builtFrom in item.BuiltFrom)
                    {
                        if (builtFrom.Total != -1)
                        {
                            total += builtFrom.Total;
                        }
                        else
                        {
                            failed = true;
                            break;
                        }
                    }

                    if (!failed)
                    {
                        item.Total = total;
                    }
                }

                iterations++;
            }
        }
    }
}
